package com.gqb.spring.framework;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;

import org.apache.commons.digester.Digester;
import org.xml.sax.SAXException;

import com.gqb.spring.bean.StringUtil;
import com.gqb.spring.tag.Bean;
import com.gqb.spring.tag.Beans;
import com.gqb.spring.tag.Property;
import com.gqb.spring.tag.Scan;

public class XmlBeanFactory extends AbstractBeanFactory {
	private AbstractBeanFactory parentFactory;
	private String beanName;
	private final String  DEFAULT_BEANNAME="beans.xml";
	public XmlBeanFactory( AbstractBeanFactory abstractBeanFactory,String beanName) {
		this.parentFactory=abstractBeanFactory;
		this.beanName=beanName;
		if(null==beanName|beanName.equals("")){
			beanName=DEFAULT_BEANNAME;
		}
	}
	

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public Object getBean(String beanId) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		Object object= super.getBeanIdObject().get(beanId);
		if(null!=object)
			return object;
		Bean bean=getBeanIdBean().get(beanId);
		if(null==bean)
			return null;
		Class  clazz=Class.forName(bean.getClassName());
		object=clazz.newInstance();
		List<Property> props= bean.getProps();
		for (Property property : props) {
			String methodName="set"+StringUtil.bigCaseFirstChar(property.getName());
			if(null!=property.getValue()){
				Method m=clazz.getMethod(methodName, String.class);
				m.setAccessible(true);
				m.invoke(object, property.getValue());
			}
			if(null!=property.getRef()){
				Object childObject=parentFactory.getBean(property.getRef());
				Class clazzChild=null;
				if(null!=getBeanIdBean().get(property.getRef())){
					clazzChild=Class.forName(getBeanIdBean().get(property.getRef()).getClassName());
				} else{
					clazzChild=getBeanIdClass().get(property.getRef());
				}
				Method m=clazz.getMethod(methodName, clazzChild);
				m.setAccessible(true);
				m.invoke(object, childObject);
			}
		}
		if(object!=null){
			addObject(beanId, object);
		}
		return object;
	}

	@Override
	public void load() throws IOException, SAXException {
		Digester digester = new Digester();
		digester.setValidating(false);
		digester.addObjectCreate("beans", Beans.class);

		// 如果配置文件中有多个bean，add一次即可
		digester.addObjectCreate("beans/bean", Bean.class);
		digester.addObjectCreate("beans/scan", Scan.class);
		// 设置bean的属性<bean name="",id="">中的id和name。默认属性名和类中的属性名一样，不同的要特殊配置
		digester.addSetProperties("beans/bean", "class", "className");
		digester.addSetProperties("beans/bean","init-method","initMethodName");
		digester.addSetProperties("beans/bean", "destroy-method", "destroyMethodName");
		digester.addSetProperties("beans/bean");
		digester.addSetProperties("beans/scan", "package", "packageName");
		digester.addSetNestedProperties("beans/scan");
		digester.addObjectCreate("beans/bean/property", Property.class);
		// 将标签中的属性赋给对象
		digester.addSetProperties("beans/bean/property");
		// 设置对象间的关系
		digester.addSetNext("beans/bean/property", "addProperty");
		digester.addSetNext("beans/bean", "addBean");
		digester.addSetNext("beans/scan", "addScan");
//		InputStream in = ClassLoader.getSystemResourceAsStream(beanName);
		InputStream in = new FileInputStream(new File(beanName));
		Beans beans = (Beans) digester.parse(in);
		List<Bean> beanList = beans.getBeans();
		List<Scan> scans=new ArrayList<Scan>();
		 scans.addAll(beans.getScans());
		for (Bean bean : beanList) {
			addBean(bean.getId(), bean);
		}
		setBeans(beans);
		in.close();
	}


	@Override
	public void setBeans(Beans beans) {
		parentFactory.setBeans(beans);
	}


	@Override
	public void addBean(String beanID, Bean bean) {
		parentFactory.addBean(beanID, bean);
	}


	@Override
	public Map<String, Bean> getBeanIdBean() {
		return parentFactory.getBeanIdBean();
	}


	@Override
	public Beans getBeans() {
		return parentFactory.getBeans();
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Map<String, Class> getBeanIdClass() {
		return parentFactory.getBeanIdClass();
	}


	@Override
	public Map<String, Object> getBeanIdObject() {
		return parentFactory.getBeanIdObject();
	}


	@Override
	public void addObject(String beanId, Object object) {
		parentFactory.addObject(beanId, object);
	}
	
	
}
